Using Interact

The interact function (IPython.html.widgets.interact) automatically creates a graphical user interface (GUI) for exploring code and data interactively. It is the easiest way to get started using IPython's widgets.


In [ ]:
from __future__ import print_function
from IPython.html.widgets import interact, interactive, fixed
from IPython.html import widgets

Basic interact

At the most basic level, interact autogenerates UI controls for function arguments, and then calls the function with those arguments when you manipulate the controls interactively. To use interact, you need to define a function that you want to explore. Here is a function that prints its only argument x.


In [ ]:
def f(x):
    print(x)

When you pass this function as the first argument to interact along with an integer keyword argument (x=10), a slider is generated and bound to the function.


In [ ]:
interact(f, x=10);

When you move the slider, the function is called and the current value of x is printed.

If you pass True or False, interact will generate a checkbox:


In [ ]:
interact(f, x=True);

If you pass a string, interact will generate a text area.


In [ ]:
interact(f, x='Hi there!');

interact can also be used as a decorator. This allows you to define a function and interact with it in a single shot. As this example shows, interact also works with functions that have multiple arguments.


In [ ]:
@interact(x=True, y=1.0)
def g(x, y):
    print(x, y)

Fixing arguments using fixed

There are times when you may want to explore a function using interact, but fix one or more of its arguments to specific values. This can be accomplished by wrapping values with the fixed function.


In [ ]:
def h(p, q):
    print(p, q)

When we call interact, we pass fixed(20) for q to hold it fixed at a value of 20.


In [ ]:
interact(h, p=5, q=fixed(20));

Notice that a slider is only produced for p as the value of q is fixed.

Widget abbreviations

When you pass an integer valued keyword argument (x=10) to interact, it generates an integer valued slider control with a range of $[-10,+3\times10]$. In this case 10 is an abbreviation for an actual slider widget:

IntSliderWidget(min=-10,max=30,step=1,value=10)

In fact, we can get the same result if we pass this IntSliderWidget as the keyword argument for x:


In [ ]:
interact(f, x=widgets.IntSliderWidget(min=-10,max=30,step=1,value=10));

This examples clarifies how interact proceses its keyword arguments:

  1. If the keyword argument is Widget instance with a value attribute, that widget is used. Any widget with a value attribute can be used, even custom ones.
  2. Otherwise, the value is treated as a widget abbreviation that is converted to a widget before it is used.

The following table gives an overview of different widget abbreviations:

Keyword argumentWidget
`True` or `False`CheckboxWidget
`'Hi there'`TextareaWidget
`value` or `(min,max)` or `(min,max,step)` if integers are passedIntSliderWidget
`value` or `(min,max)` or `(min,max,step)` if floats are passedFloatSliderWidget
`('orange','apple')` or `{'one':1,'two':2}`Dropdown

You have seen how the checkbox and textarea widgets work above. Here, more details about the different abbreviations for sliders and dropdowns are given.

If a 2-tuple of integers is passed (min,max) a integer valued slider is produced with those minimum and maximum (inclusive) values. In this case, the default step size of 1 is used.


In [ ]:
interact(f, x=(0,4));

If a 3-tuple of integers is passed (min,max,step) the step size can also be set.


In [ ]:
interact(f, x=(0,8,2));

A float valued slider is produced if the elements of the tuples are floats. Here the minimum is 0.0, the maximum is 10.0 and step size is 0.1 (the default).


In [ ]:
interact(f, x=(0.0,10.0));

The step size can be changed by passing a 3rd element in the tuple.


In [ ]:
interact(f, x=(0.0,10.0,0.01));

For both integer and float valued sliders, you can pick the initial value of the widget by passing a default keyword argument to the underlying Python function. Here we set the initial value of a float slider to 5.5.


In [ ]:
def h(x=5.5):
    print(x)
    
interact(h, x=(0.0,20.0,0.5));

Dropdown menus can be produced by passing a tuple of strings. In this case, the strings are both used as the names in the dropdown menu UI and passed to the underlying Python function.


In [ ]:
interact(f, x=('apples','oranges'));

If you want a dropdown menu that passes non-string values to the Python function, you can pass a dictionary. The keys in the dictionary are used for the names in the dropdown menu UI and the values are the arguments that are passed to the underlying Python function.


In [ ]:
interact(f, x={'one': 10, 'two': 20});

interactive

In addition to interact IPython provides another function, interactive, that is useful when you want to reuse the widget that are produced or access the data that is bound to the UI controls.

Here is a function that returns the sum of its two arguments.


In [ ]:
def f(a, b):
    return a+b

Unlike interact, interactive returns a Widget instance rather than immediately displaying the widget.


In [ ]:
w = interactive(f, a=10, b=20)

The widget is a ContainerWidget, which is a container for other widgets.


In [ ]:
type(w)

The children of the ContainerWidget are two integer valued sliders produced by the widget abbreviations above.


In [ ]:
w.children

To actually display the widgets, you can use IPython's display function.


In [ ]:
from IPython.display import display
display(w)

Or return the value


In [ ]:
w

At this point, the UI controls work just like they would if interact had been used. You can manipulate them interactively and the function will be called. However, the widget instance returned by interactive also give you access to the current keyword arguments and return value of the underlying Python function.

Here are the current keyword arguments. If you rerun this cell after manipulating the sliders, the values will have changed.


In [ ]:
w.kwargs

Here is the current return value of the function.


In [ ]:
w.result

Plotting with Matplotlib

IPython works with the Matplotlib plotting library, which integrates Matplotlib with IPython's display system and event loop handling.

matplotlib mode

To make plots using Matplotlib, you must first enable IPython's matplotlib mode.

To do this, run the %matplotlib magic command to enable plotting in the current Notebook.

This magic takes an optional argument that specifies which Matplotlib backend should be used. Most of the time, in the Notebook, you will want to use the inline backend, which will embed plots inside the Notebook:


In [ ]:
%matplotlib inline

You can also use Matplotlib GUI backends in the Notebook, such as the Qt backend (%matplotlib qt). This will use Matplotlib's interactive Qt UI in a floating window to the side of your browser. Of course, this only works if your browser is running on the same system as the Notebook Server. You can always call the display function to paste figures into the Notebook document.

Making a simple plot

With matplotlib enabled, plotting should just work.


In [ ]:
import matplotlib.pyplot as plt
import numpy as np

In [ ]:
x = np.linspace(0, 3*np.pi, 500)
plt.plot(x, np.sin(x**2))
plt.title('A simple chirp');

These images can be resized by dragging the handle in the lower right corner. Double clicking will return them to their original size.

One thing to be aware of is that by default, the Figure object is cleared at the end of each cell, so you will need to issue all plotting commands for a single figure in a single cell.

For vector image plots, use the following config.


In [ ]:
%config InlineBackend.figure_format = 'svg'

In [ ]:
x = np.linspace(0, 3*np.pi, 500)
plt.plot(x, np.sin(x**2))
plt.title('A simple chirp');

Loading Matplotlib demos with %load

IPython's %load magic can be used to load any Matplotlib demo by its URL:


In [ ]:
%load http://matplotlib.org/mpl_examples/showcase/integral_demo.py

In [ ]:
"""
Plot demonstrating the integral as the area under a curve.

Although this is a simple example, it demonstrates some important tweaks:

    * A simple line plot with custom color and line width.
    * A shaded region created using a Polygon patch.
    * A text label with mathtext rendering.
    * figtext calls to label the x- and y-axes.
    * Use of axis spines to hide the top and right spines.
    * Custom tick placement and labels.
"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon


def func(x):
    return (x - 3) * (x - 5) * (x - 7) + 85


a, b = 2, 9 # integral limits
x = np.linspace(0, 10)
y = func(x)

fig, ax = plt.subplots()
plt.plot(x, y, 'r', linewidth=2)
plt.ylim(ymin=0)

# Make the shaded region
ix = np.linspace(a, b)
iy = func(ix)
verts = [(a, 0)] + list(zip(ix, iy)) + [(b, 0)]
poly = Polygon(verts, facecolor='0.9', edgecolor='0.5')
ax.add_patch(poly)

plt.text(0.5 * (a + b), 30, r"$\int_a^b f(x)\mathrm{d}x$",
         horizontalalignment='center', fontsize=20)

plt.figtext(0.9, 0.05, '$x$')
plt.figtext(0.1, 0.9, '$y$')

ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.xaxis.set_ticks_position('bottom')

ax.set_xticks((a, b))
ax.set_xticklabels(('$a$', '$b$'))
ax.set_yticks([])

plt.show()

Interactive Plots

Interact can also be used with almost any function with supported parameter types, including those that output matplotlib plots. In the following example, a function that plots the sum of two sine waves is interacted with.


In [ ]:
@interact(frequency1=20., frequency2=21.)
def plot_waves(frequency1, frequency2):
    x = np.linspace(0, 3*np.pi, 500)
    plt.plot(x, np.sin(x*frequency1) + np.sin(x*frequency2))

Exercises

String sorting

  • Write a sort_string function that takes a string as its input and prints a new string consisting of the original one, sorted.
  • Add a reverse keyword argument with a default of False to allow for the sorting to be done in reverse.
  • Then, use interact to create a user interface for exploring your sort_string function.

In [ ]:


In [ ]:
%load soln/string_sorting.py

Plotting with parameters

Write a plot_sin function that plots $sin(ax+b)$ over the interval [0,4π].
Then use interact to create a user interface for exploring your function:

  • a should be a floating point number over the interval [0.0,5.0].
  • b should be a floating point number over the interval [−5.0,5.0].

In [ ]:


In [ ]:
%load soln/param_plot_1.py

In matplotlib, the line style and color can be set with a third argument to plot. Examples of this argument:
dashed red: r--
blue circles: bo
dotted black: k.

Add a style argument to your plot_sin function that allows you to set the line style of the plot.

Use interact to create a UI for plot_sin that has a drop down menu for selecting the line style between a dotted red line and a dashed black line. This time use interact as a decorator.


In [ ]:


In [ ]:
%load soln/param_plot_2.py